﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.UI;
using Thesis_NCDat;

namespace BKBIS
{
    /// <summary>
    /// Lớp này chứa các hàm liên quan đến thao tác chuột trên imagebox1
    /// </summary>
    class MouseEventInImageBox
    {
        public void Mouseup_Detectellipse(bool hsv, bool ycc, Image<Hsv, Byte> imghsv, Image<Ycc, Byte> imgycc,
           out Image<Hsv, Byte> hsvROI, out Image<Ycc, Byte> yccROI, Rectangle rect, out int[] average, out bool shape, int threshvalue)
        {
            average = new int[3];                       // khai báo mảng 3 phần tử là 3 số nguyên chứa giá trị màu trung bình của mỗi kênh h,h,v hoặc cb, cy, cr

            CvInvoke.cvSetImageROI(imghsv, rect);
            hsvROI = imghsv.Copy();
            CvInvoke.cvResetImageROI(imghsv);
            CvInvoke.cvSetImageROI(imgycc, rect);
            yccROI = imgycc.Copy();
            CvInvoke.cvResetImageROI(imgycc);

            ImageProcessing newprocess = new ImageProcessing();                                  // tạo mới đối tượng newprocess để tí nữa gọi hàm check_shape_ellipse
            Image<Hsv, Byte> hsvROI2 = hsvROI.Copy();                                            // tạo một bản sao hsvROI, chưa thấy dùng làm gì cả
            BlisterFeatures newdata = new BlisterFeatures();                                     // tạo mới đối tượng newdata vì nó là tham số trong hàm check_shape_ellipse sẽ được gọi ở bên dưới
            bool size;                                                                           // tạo mới tham số để đưa vào check_shape_ellipse
            int tole1 = 0, tole2 = 0, area = 0;                                                  // tole là "tolerance", tạo mới tham số để đưa vào check_shape_ellipse
            Image<Gray, Byte> channel1 = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height),     // tạo ra 3 kênh channel 1,2,3 vì chúng là tham số trong hàm FindAverageOfColor sẽ được gọi ở bên dưới nhằm mục đích tính ra giá trị màu h,s,v trung bình tương ứng với average[0],[1],[2]
                              channel2 = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height),
                              channel3 = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height),
                              newgray = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height),     // tao tạo ra 2 ảnh newgray và newbin để tí nữa ta gọi hàm "check_shape_ellipse" có cái để đưa vào parameters.
                              newbin = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height);      // newbin: bin ở đây là Bgr_image_INput tức là Brg thực ra là ảnh RGB

            
            if (hsv)
            {
                channel1 = hsvROI.Split()[0];
                channel2 = hsvROI.Split()[1];
                channel3 = hsvROI.Split()[2];
                newbin = newgray = hsvROI.Convert<Gray, Byte>();        // chuyển hsvROI thành ảnh xám, lưu vào 2 biến này vì chúng là tham số của hàm check_shape_ellipse được gọi bên dưới
                
            }
            else if (ycc)
            {
                channel1 = yccROI.Split()[0];
                channel2 = yccROI.Split()[1];
                channel3 = yccROI.Split()[2];
                newbin = newgray = yccROI.Convert<Gray, Byte>();
            }
            Rectangle rect_ellipse;         // parameter của hàm check_shape_ellipse được gọi bên dưới
            newprocess.check_shape_ellipse(newgray, newbin, out shape, out size, out area, tole1, tole2, newdata, out rect_ellipse, threshvalue);         // gọi hàm kiểm tra hình dạng ellipse, giá trị trả về: out shape, out size, out int area, Rectangle rect_ellipse
            Train train1 = new Train();
            Rectangle[] rect1 = new Rectangle[3];       // tạo hcn này không biết để làm gì. dư thừa

            if (shape)      // nếu đúng là hình ellipse
            {

                CircleF newcircle = new CircleF(new PointF(rect_ellipse.X + rect_ellipse.Width / 2, rect_ellipse.Y + rect_ellipse.Height / 2), Math.Min(rect_ellipse.Width, rect_ellipse.Height) / 2);      // tạo một hình tròn đại diện cho viên thuốc vừa tìm được với tham số là: tâm và bán kính
                train1.FindAverageOfColor(channel1, newcircle, out average[0]);
                train1.FindAverageOfColor(channel2, newcircle, out average[1]);
                train1.FindAverageOfColor(channel3, newcircle, out average[2]);

            }
        }


        /// <summary>
        /// hàm xử lý sự kiện thả chuột trên imagebox
        /// </summary>
        /// <param name="_hsvImage"> ảnh đầu vào hsv </param>
        /// <param name="rect1"> khung chữ nhật tạo bởi mouse </param>
        /// <param name="_circles"> tọa độ hình tròn biểu thị cho viên thuốc mà chương trình nhận dạng được</param>
        /// <param name="sum"> tổng giá trị màu sắc tất cả các viên thuốc</param>
        /// <param name="count">tổng số điểm ảnh các viên thuốc</param>
        /// <param name="average">giá tị trung bình của 1 điểm ảnh trong viên thuốc</param>

        public void MouseUp_DetectCircle(bool hsv, bool ycc, Image<Hsv, Byte> _hsvImage, Image<Ycc, Byte> _yccImage,
            out Image<Hsv, Byte> _hsvImageROI, out Image<Ycc, Byte> _yccImageROI, Rectangle rect1,
            out CircleF[] _circles, out int[] average,bool thresh, int threshvalue)
        {
            Filter FilterImage = new Filter();
            Train newtrain = new Train();
          
            average = new int[3];                                                                    // khai báo mảng 3 phần tử là 3 số nguyên chứa giá trị màu trung bình của mỗi kênh h,h,v hoặc cb, cy, cr
           
            _circles = new CircleF[0];       
        
            // copy phẩn ảnh cần quan tâm vào hcn rect1
            CvInvoke.cvSetImageROI(_hsvImage, rect1);   // Sets an image Region Of Interest (ROI) for a given rectangle.
            _hsvImageROI = _hsvImage.Copy();            // Make a copy of the image, if ROI is set, only copy the ROI
            CvInvoke.cvResetImageROI(_hsvImage);        // Releases image ROI. After that the whole image is considered selected
            CvInvoke.cvSetImageROI(_yccImage, rect1);
            _yccImageROI = _yccImage.Copy();
            CvInvoke.cvResetImageROI(_yccImage);

            

            // lấy mẫu và chuyển sang ảnh xám phẩn ảnh cần quan tâm (ROI) ở trên
            Image<Gray, Byte> _grayImage1 = _hsvImageROI.Convert<Gray, Byte>().PyrDown().PyrUp();       // Performs Down/Up sampling step of Gaussian pyramid decomposition
            Image<Gray, Byte> _grayImage2 = _yccImageROI.Convert<Gray, Byte>().PyrDown().PyrUp();
            Image<Gray, Byte> channel1 = _grayImage1.CopyBlank(), channel2 = _grayImage1.CopyBlank(), channel3 = _grayImage1.CopyBlank();   // Create an image of the same size, the initial pixel in the image equals zero
            if (hsv)           
            {
                if (thresh)     // thresh là gì ?
                {
                    _circles = FilterImage.CannyFilter(_grayImage1, threshvalue, 30);
                }
                else    // làm gì đây?
                {
                    _circles = FilterImage.CannyFilter(_grayImage1,
                        Math.Max(_grayImage1.Data[_grayImage1.Height/2, _grayImage1.Width/2, 0],
                            _grayImage1.Data[_grayImage1.Height - 1, _grayImage1.Width - 1, 0]),
                        Math.Min(_grayImage1.Data[_grayImage1.Height/2, _grayImage1.Width/2, 0],
                            _grayImage1.Data[_grayImage1.Height - 1, _grayImage1.Width - 1, 0]));
                }
                if (_circles.Count() != 0)                  // trả về số hình tròn đếm được
                {
                    channel1 = _hsvImageROI.Split()[0];     // tách ảnh ra thành 3 mảng, mỗi mảng là 1 kênh đại diện cho 1 màu trong 3 màu của hệ màu đó.
                    channel2 = _hsvImageROI.Split()[1];
                    channel3 = _hsvImageROI.Split()[2];
                }
            }
            else if (ycc)       // tương tự, nếu hệ màu ycc được chọn
            {
                if (thresh)
                {
                    _circles = FilterImage.CannyFilter(_grayImage2, threshvalue, 30);
                }
                else
                {
                    _circles = FilterImage.CannyFilter(_grayImage2,
                        Math.Max(_grayImage2.Data[_grayImage2.Height/2, _grayImage2.Width/2, 0],
                            _grayImage2.Data[_grayImage2.Height - 1, _grayImage2.Width - 1, 0]),
                        Math.Min(_grayImage2.Data[_grayImage2.Height/2, _grayImage2.Width/2, 0],
                            _grayImage2.Data[_grayImage2.Height - 1, _grayImage2.Width - 1, 0]));
                }
                if (_circles.Count() != 0)
                {
                    channel1 = _yccImageROI.Split()[0];
                    channel2 = _yccImageROI.Split()[1];
                    channel3 = _yccImageROI.Split()[2];
                }
               
            }
            if (_circles.Count() != 0)
            {
                newtrain.FindAverageOfColor(channel1, _circles[0], out average[0]);
                newtrain.FindAverageOfColor(channel2, _circles[0], out average[1]);
                newtrain.FindAverageOfColor(channel3, _circles[0], out average[2]);
            }
        }

        /// <summary>
        /// Hàm này phát hiện có hình vuông hay không khi có sự kiện mouseup (thả chuột)
        /// </summary>
        /// <param name="hsv"></param>
        /// <param name="ycc"></param>
        /// <param name="imghsv">ảnh đầu vào hệ màu hsv</param>
        /// <param name="imgycc">ảnh đầu vào hệ màu ycc</param>
        /// <param name="hsvROI">ảnh ngõ ra chứa vùng cần quan tâm (ROI) từ ảnh ban đầu, hệ màu hsv</param>
        /// <param name="yccROI">ảnh ngõ ra chứa vùng cần quan tâm (ROI) từ ảnh ban đầu, hệ màu ycc</param>
        /// <param name="rect"></param>
        /// <param name="average">mảng ngõ ra chứa 3 giá trị trung bình của 3 màu h,s,v</param>
        /// <param name="shape">biến ngõ ra cho biết có hình vuông hay không</param>
        /// <param name="threshvalue"></param>
        public void MouseUp_DetectSquare(bool hsv, bool ycc, Image<Hsv, Byte> imghsv, Image<Ycc, Byte> imgycc,
           out Image<Hsv, Byte> hsvROI, out Image<Ycc, Byte> yccROI, Rectangle rect, out int[] average, out bool shape, int threshvalue)
        {
            // copy vùng ảnh cần quan tâm
            CvInvoke.cvSetImageROI(imghsv, rect);
            hsvROI = imghsv.Copy();
            CvInvoke.cvResetImageROI(imghsv);
            CvInvoke.cvSetImageROI(imgycc, rect);
            yccROI = imgycc.Copy();
            CvInvoke.cvResetImageROI(imgycc);

            Image<Gray, Byte> channel1 = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height),        // tạo ra 3 kênh channel 1,2,3 vì chúng là tham số trong hàm FindAverageOfColor sẽ được gọi ở bên dưới nhằm mục đích tính ra giá trị màu h,s,v trung bình tương ứng với average[0],[1],[2]
                              channel2 = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height),
                              channel3 = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height),
                              newgray = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height),     // tao tạo ra 2 ảnh newgray và newbin để tí nữa ta gọi hàm "check_shape_ellipse" có cái để đưa vào parameters.
                              newbin = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height);      // newbin: bin ở đây là Bgr_image_INput tức là Brg thực ra là ảnh RGB

            if (hsv)
            {
                channel1 = hsvROI.Split()[0];
                channel2 = hsvROI.Split()[1];
                channel3 = hsvROI.Split()[2];
                newbin = newgray = hsvROI.Convert<Gray, Byte>();        // chuyển hsvROI thành ảnh xám, lưu vào 2 biến này vì chúng là tham số của hàm check_shape_square được gọi bên dưới
            }
            else if (ycc)
            {
                channel1 = yccROI.Split()[0];
                channel2 = yccROI.Split()[1];
                channel3 = yccROI.Split()[2];
                newbin = newgray = hsvROI.Convert<Gray, Byte>();        // chuyển hsvROI thành ảnh xám, lưu vào 2 biến này vì chúng là tham số của hàm check_shape_square được gọi bên dưới
            }

            BlisterFeatures newdata = new BlisterFeatures();
            bool size;                                                                           // tạo mới tham số để đưa vào check_shape_square
            int tole1 = 0, tole2 = 0, area = 0;                                                  // tole là "tolerance", tạo mới tham số để đưa vào check_shape_square
            average = new int[3];                                   // khai báo mảng 3 phần tử là 3 số nguyên chứa giá trị màu trung bình của mỗi kênh h,h,v hoặc cb, cy, cr
            Rectangle rect_square;                                  // tạo mới một hcn rect_square vì nó là tham số của hàm check_shape_square được gọi bên dưới
            ImageProcessing newprocess = new ImageProcessing();     // tạo ra đối tượng newprocess để tí nữa ta gọi hàm check hình vuông "check_shape_square" trong file "ImageProcessing"

            newprocess.check_shape_square(newgray, newbin, out shape, out size, out area, tole1, tole2, newdata, out rect_square, threshvalue);                        // gọi hàm kiểm tra hình dạng square, giá trị trả về: out shape, out size, out int area
            
            Train train2 = new Train();     // tạo ra đối tượng train2 để tí nữa gọi hàm FindAverageOfColor trong lớp Train
            if (shape)                      // nếu đúng là hình vuông
            {

                CircleF newcircle = new CircleF(new PointF(rect_square.X + rect_square.Width / 2, rect_square.Y + rect_square.Height / 2), Math.Min(rect_square.Width, rect_square.Height) / 2);        // tạo ra 1 hình tròn với: tâm là tâm viên thuốc đầu tiên, bán kính = (cạnh bé hơn của hcn/2)
                train2.FindAverageOfColor(channel1, newcircle, out average[0]);
                train2.FindAverageOfColor(channel2, newcircle, out average[1]);
                train2.FindAverageOfColor(channel3, newcircle, out average[2]);

            }
        }
        public void MouseUp_DetectCapsule(bool hsv, bool ycc, Image<Hsv, Byte> imghsv, Image<Ycc, Byte> imgycc,
           out Image<Hsv, Byte> hsvROI, out Image<Ycc, Byte> yccROI, Rectangle rect, out int[] average, out bool shape, int threshvalue)
        {
            // copy vùng ảnh cần quan tâm
            CvInvoke.cvSetImageROI(imghsv, rect);
            hsvROI = imghsv.Copy();
            CvInvoke.cvResetImageROI(imghsv);
            CvInvoke.cvSetImageROI(imgycc, rect);
            yccROI = imgycc.Copy();
            CvInvoke.cvResetImageROI(imgycc);

            Image<Gray, Byte> channel1 = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height),        
                              channel2 = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height),
                              channel3 = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height),
                              newgray = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height),     // tao tạo ra 2 ảnh newgray và newbin để tí nữa ta gọi hàm "check_shape_ellipse" có cái để đưa vào parameters.
                              newbin = new Image<Gray, Byte>(hsvROI.Width, hsvROI.Height);      // newbin: bin ở đây là Bgr_image_INput tức là Brg thực ra là ảnh RGB

            if (hsv)
            {
                channel1 = hsvROI.Split()[0];       // trung bình h
                channel2 = hsvROI.Split()[1];       // trung bình s
                channel3 = hsvROI.Split()[2];       // trung bình v
                newbin = newgray = hsvROI.Convert<Gray, Byte>();        // parameter của "check_shape_square" được gọi bên dưới
            }
            else if (ycc)
            {
                channel1 = yccROI.Split()[0];
                channel2 = yccROI.Split()[1];
                channel3 = yccROI.Split()[2];
                newbin = newgray = hsvROI.Convert<Gray, Byte>();        // chuyển hsvROI thành ảnh xám, lưu vào 2 biến này vì chúng là tham số của hàm check_shape_square được gọi bên dưới
            }

            BlisterFeatures newdata = new BlisterFeatures();
            bool size;                                              // tạo mới tham số để đưa vào "check_shape_square"
            int tole1 = 0, tole2 = 0, area = 0;                     // tole là "tolerance" khai báo cho có, còn area chứa giá trị diện tích
            average = new int[3];                                   // khai báo mảng 3 phần tử là 3 số nguyên chứa giá trị màu trung bình của mỗi kênh h,h,v hoặc cb, cy, cr
            Rectangle rect_square;                                  // parameter of "check_shape_square" được gọi bên dưới
            ImageProcessing newprocess = new ImageProcessing();     // tạo ra đối tượng newprocess để tí nữa ta gọi hàm check hình vuông "check_shape_square" trong file "ImageProcessing"

            newprocess.check_shape_capsule(newgray, newbin, out shape, out size, out area, tole1, tole2, newdata, out rect_square, threshvalue);                        // gọi hàm kiểm tra hình dạng square, giá trị trả về: out shape, out size, out int area

            Train train2 = new Train();     // tạo ra đối tượng train2 để tí nữa gọi hàm FindAverageOfColor trong lớp Train
            if (shape)                      // nếu đúng là capsule
            {
                // tạo ra 1 hình tròn với: tâm là tâm viên thuốc đầu tiên, bán kính = (cạnh bé hơn của hcn/2)
                CircleF newcircle = new CircleF(new PointF(rect_square.X + rect_square.Width / 2, rect_square.Y + rect_square.Height / 2), Math.Min(rect_square.Width, rect_square.Height) / 2);        
                train2.FindAverageOfColor(channel1, newcircle, out average[0]);
                train2.FindAverageOfColor(channel2, newcircle, out average[1]);
                train2.FindAverageOfColor(channel3, newcircle, out average[2]);

            }
        }
       
        /// <summary>
        /// hàm xử lý sự kiện nhấn chuột trái
        /// </summary>
        /// <param name="e"> sự kiện chuột </param>
        /// <param name="initialX"> tọa độ x nơi xảy ra sự kiện</param>
        /// <param name="initialY">tọa độ y nơi xảy ra sự kiện</param>
        /// <param name="width"> bề rộng hình chữ nhật cần vẽ</param>
        /// <param name="height">chiều cao hình chữ nhật cần vẽ</param>
        public void MouseDownEvent(MouseEventArgs e, out int initialX,out int initialY,out int width, out int height)
        {
                initialX = e.X;
                initialY = e.Y;
                width = 0;
                height = 0;
            
        }
    }
}
